package com.wss.lsl.test.driven.part2;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.io.StringWriter;

import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

public abstract class VelocityTestCase {

	private VelocityContext velocityContext;
	private Document document;

	@Before
	public void setUp() throws Exception {
		velocityContext = new VelocityContext();
	}

	protected void setAttribute(String key, String value) {
		velocityContext.put(key, value);
	}

	protected String getWebRoot() {
		return "";
	}

	protected void render(String templatePath) throws Exception {
		File templateFile = new File(getWebRoot(), templatePath);
		String template = readFileContent(templateFile);
		String renderedHtml = renderTemplate(template);
		this.document = parseAsXml(renderedHtml);
	}

	private Document parseAsXml(String renderedHtml)
			throws ParserConfigurationException, SAXException, IOException {

		InputSource is = new InputSource(new StringReader(renderedHtml));
		DocumentBuilder db = DocumentBuilderFactory.newInstance()
				.newDocumentBuilder();
		Document document = db.parse(is);

		return document;
	}

	protected void assertFormFieldValue(String fieldName, String expectedValue)
			throws XPathExpressionException {
		String xpath = xpathForField(fieldName);
		assertNodeExists(xpath);
		String actual = getString(xpath + "/@value");
		Assert.assertEquals(expectedValue, actual);
	}

	private String getString(String xpath) throws XPathExpressionException {
		return (String) evaluate(xpath, XPathConstants.STRING);
	}

	private void assertNodeExists(String xpath) throws XPathExpressionException {

		Assert.assertNotNull("Node doesn't exists: " + xpath, getNode(xpath));
	}

	private Node getNode(String xpath) throws XPathExpressionException {
		return (Node) evaluate(xpath, XPathConstants.NODE);
	}

	private Object evaluate(String xpath, QName node)
			throws XPathExpressionException {

		XPath engine = XPathFactory.newInstance().newXPath();
		return engine.evaluate(xpath, this.document, node);
	}

	private String xpathForField(String fieldName) {
		return "//form//input[@name='" + fieldName + "']";
	}

	private String renderTemplate(String template) {
		VelocityEngine engine = new VelocityEngine();
		engine.init();

		StringWriter html = new StringWriter();
		engine.evaluate(velocityContext, html, "test", template);
		return html.toString();
	}

	private String readFileContent(File templateFile) throws IOException {
		System.out.println(templateFile.getAbsolutePath());
		BufferedReader reader = new BufferedReader(new InputStreamReader(
				new FileInputStream(templateFile), "UTF-8"));
		StringBuilder template = new StringBuilder();
		String buffered = null;
		while ((buffered = reader.readLine()) != null) {
			template.append(buffered);
		}
		reader.close();
		return template.toString();
	}

	public VelocityTestCase() {
	}

	@Test
	public final void _1() {
	}

}
